Image warping correction in forming 360 degree panoramic images

ABSTRACT

A method for creating a 360 degree panoramic image from multiple images includes (1) computing a gross rotation error ΔR between a first image and a calculated first image rotated to be stitched to a last image, and (2) spreading the gross rotation error ΔR to each pixel on the panoramic image. Spreading the gross rotation error ΔR includes (1) computing a rotation angle θ 0  and rotational axis n 0  from the gross rotational error ΔR, (2) determining an angle α of each pixel, and (3) determining a compensation matrix R c  for each pixel using the following formula: R,(a)=R(2π/αθ 0 ). Spreading the gross rotation error ΔR further includes (4) tracing a pixel on the panoramic image to a camera optical center of the images to form a first ray, (5) determining a second ray originating from the camera optical center that would be rotated by the compensation matrix R c  to coincide with the first ray, (6) tracing the second ray to a second pixel on one of the images, and (7) painting the first pixel with color values of the second pixel.

FIELD OF THE INVENTION

[0001] This invention relates to digital image stitching and in particular to an image stitching method for generating a 360 degree panoramic image from a sequence of images.

DESCRIPTION OF RELATED ART

[0002] Digital photography is becoming more popular today as digital cameras and scanners are becoming widely available. Digital images can be created either by capturing a scene using a digital camera or digitizing a traditional film-based photograph using a scanner. One particular advantage of digital photography over traditional film-based photography is that digital images can be easily manipulated or edited for better presentation. Digital photography can also be readily distributed over the Internet.

[0003] When a photographer captures a scene using a camera, the desired field of view may be larger than the normal field of view of the camera. Digital photography allows a panoramic image to be produced without the need of purchasing special equipment such as a panoramic camera or fisheye lenses. For example, a photographer with a digital camera may capture a series of digital pictures of a scene by rotating the camera and taking pictures in a sequence of different directions. The captured images may then be stitched together to produce a panoramic picture of the scene. Similarly, film-based photographs can be digitized, and the panoramic picture can be composed by stitching together the digitized images. Presently, digital image programs are available for stitching multiple digital images together to form a panoramic picture. Exemplary programs include Ulead Cool 360™, Live Picture PhotoVista™, and MGI PhotoSuite III™.

[0004] Typically a conventional image program stitches images by matching corresponding features on two source images and rotating one source image so the corresponding features overlap. For example, a 360 degree panoramic image is constructed from a sequence of many images where the last image is stitched to the first image to complete the 360 degree view. However, errors (e.g., matching and motion estimation errors) cause a gap between the last image and the first image that must be compensated so they can be stitched together. Therefore, there is a need for a method to compensate these errors in a reasonable way so the last image can be stitched to the first image.

SUMMARY OF THE INVENTION

[0005] In one embodiment, a method for creating a 360 degree panoramic image from multiple images includes (1) computing a gross rotation error ΔR between a first image and a calculated first image rotated to be stitched to a last image, and (2) spreading the gross rotation error ΔR to each pixel of the panoramic image. In one embodiment, spreading the gross rotation error ΔR includes (1) computing a rotation angle θ₀ and rotational axis n₀ from the gross rotational error ΔR, (2) determining an angle α of each pixel, and (3) determining a compensation matrix R_(c) for each pixel using the following formula: ${R_{c}(\alpha)} = {{R\left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}.}$

[0006] In one embodiment, spreading the gross rotation error ΔR further includes (4) tracing a pixel in a column on the panoramic image to a camera optical center of the images to form a first ray, (5) determining a second ray originating from the camera optical center that would be rotated by the compensation matrix R_(c) to coincide with the first ray, (6) tracing the second ray to a second pixel on one of the images, and (7) painting the first pixel with color values of the second pixel.

BRIEF DESCRIPTION OF THE DRAWINGS

[0007]FIG. 1 illustrates a diagram of a sequence of stitched images to be projected on a cylindrical surface to generate a 360 degree panoramic image in one embodiment of the invention.

[0008]FIG. 2 illustrates a flowchart of a method to generate a 360 degree panoramic image in one embodiment of the invention.

[0009]FIG. 3A illustrates the relative rotation between two adjacent images where the rotation is represented by a rotational axis and a rotational angle in one embodiment.

[0010]FIG. 3B illustrates the relative rotation between two an original first image and a rotated first image that can be stitched to the last image where the rotation is represented by a rotational axis and a rotational angle in one embodiment.

[0011]FIG. 4 illustrates an angle of a column on the cylindrical surface used to calculate a compensation rotation matrix R_(c) in one embodiment.

[0012]FIG. 5 illustrates the compensation of a pixel on the cylindrical surface using the compensation rotation matrix R_(c) in one embodiment.

DETAILED DESCRIPTION

[0013] In one embodiment of the invention, a computer generates a 360 degree panoramic image by determining the focal length of the camera, matching feature points between adjacent images, and using the focal length and the feature points to determine the positions of the adjacent images around a fixed camera optical center. The computer assumes that the adjacent images are taken by a camera rotated from the fixed camera optical center. After the images are arranged about the camera optical center, their pixels can be projected onto a cylindrical surface (or vice versa) to generate the 360 degree panoramic image. For additional details regarding determining the focal length, matching feature points, and determining the position of adjacent images, please see U.S. patent application Ser. No. 09/665,917, filed Sep. 20, 2001, which is incorporated by reference in its entirety.

[0014]FIG. 1 illustrates an exemplary sequence of images P[0], P[1], . . . , P[9] arranged around a camera optical center O in one embodiment of the invention. Camera optical center O is also the origin of a coordinate system XYZ. The pixels of images P[0] to P[9] can be projected onto a cylindrical surface 102 to generate a 360 degree panoramic image. Although ten images are shown, any number of images around the origin O may be used.

[0015] The relative rotation matrices between adjacent images P[0] and P[1], P[1] and P[2], . . . and P[8] and P[9] can be defined as R_(H)[0], R_(H)[1], . . . , and R_(H)[9], where “R” means “rotation” and “H” means the rotation is a relative motion in the horizontal direction. The absolute rotation matrices for images P[0], P[1], . . . , and P[9] can be defined as R[0], R[1], . . . , and R[9]. Accordingly,

[0016] R[0]=1

[0017] R[1]=R_(H)[0]*R[0]

[0018] R[2]=R_(H)[1]* R[1]

[0019] . . .

[0020] R[9]=R_(H)[8]* R[8]

[0021] R′[0]=R_(H)[9]* R[9],

[0022] where I is an identity matrix.

[0023] If there is n₀ matching or motion estimation error, R′[0] should be an identity matrix like R[0]. In reality, R′[0] is not an identity matrix because of the matching and motion estimation errors. For images P[0] to P[9] to be seamlessly stitched, the computer must make R′[0]=R[0]=1.

[0024] If R′[0]*ΔR=R[0]=I, then ΔR=(R′[0])⁻¹. ΔR is defined as the gross rotation error for matching and motion estimation. ΔR is the rotation necessary to rotate a calculated first image P′[0] to overlap the original first image P[0], where the calculated first image P′[0] is the first image P[0] rotated to be stitched to the last image P[9]. In other words, this is the rotation matrix needed to rotate the original first image P[0] to match the last image P[9] so they can be stitched together to from the 360 degree panoramic image. There is a need for an algorithm to spread the gross error ΔR in the stitched image so the last image P[9] can be stitched to the first image P[0].

[0025]FIG. 2 illustrates a method 200 to generate a 360 degree panoramic image in one embodiment of the invention. In action 202, the computer receives input of the image sequence (e.g., images P[0] to P[9] in FIG. 1). The camera focus length and relative rotation matrices between adjacent images have been previously determined by the computer as described in U.S. patent application Ser. No. 09/665,917.

[0026] In action 204, the computer calculates the gross rotational matrix ΔR from the relative rotation matrices using the following formula:

ΔR=(R′[0])⁻¹.

[0027] ΔR is the relative rotation matrix between the original first image P[0] and the calculated first image P′[0] that can be stitched to the last image P[9].

[0028] In action 206, the computer calculates the rotational axis form of the gross rotational matrix ΔR. The rotational axis form is defined by a rotation axis and a rotational angle α follows: $R = {\begin{bmatrix} {n_{1}^{2} + {\left( {1 - n_{1}^{2}} \right)\cos \quad \theta}} & {{n_{1}{n_{2}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{3}\sin \quad \theta}} & {{n_{1}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{2}\sin \quad \theta}} \\ {{n_{1}{n_{2}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{3}\sin \quad \theta}} & {n_{2}^{2} + {\left( {1 - n_{2}^{2}} \right)\cos \quad \theta}} & {{n_{2}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{1}\sin \quad \theta}} \\ {{n_{1}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{2}\sin \quad \theta}} & {{n_{2}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{1}\sin \quad \theta}} & {n_{3}^{2} + {\left( {1 - n_{3}^{2}} \right)\cos \quad \theta}} \end{bmatrix}.}$

[0029] As shown in FIG. 3A, θ is the rotation angle between from image P[i] to image P[i+1] (where i is a variable) and n=[n₁, n₂, n₃]T is the rotation axis (i.e., a unit directional vector) started from origin O.

[0030] As shown in FIG. 3B, θ₀ is the rotation angle from the calculated first image P′[0] to the original first image P[0], and n₀ is the rotation axis. Since multiple relative rotation matrices are known from action 202 (e.g., R_(H)[0] to R_(H)[9]), n₀ and θ₀ can be calculated by solving the above 4-parameter rotation matrix R equation for these relative rotation matrices.

[0031] In action 208, the computer computes the size of cylindrical surface 102 (i.e., the size of the final 360 panoramic image). The size of cylindrical surface 102 is determined by its radius, which can be arbitrary. In one embodiment, the user sets the radius by selecting (1) the average focal length, (2) ½ of the average focal length, and (3) ¼ of the average focal length.

[0032] In action 210, the computer selects a starting column Q (FIG. 4) on cylindrical surface 102.

[0033] In action 212, the computer selects a starting pixel P_(f) (FIG. 4) in the selected column. Pixel P_(f) has a position of (x₁, y₁, z₁).

[0034] In action 214, the computer compensates current pixel P_(f) (i.e., the selected pixel) with a rotational compensation matrix R_(c) matrix. The rotational compensation matrix R_(c) for pixel P_(f) can be used for all the pixels in the same column (e.g., all the pixels in selected column Q) to reduce the computational cost. Rotational compensation matrix R_(c) is the gross rotational matrix ΔR spread out among each of the columns on cylindrical surface 102. As unit directional vector n₀ and rotational angle θ₀ are calculated in action 206, then the compensation rotation matrix R_(c) can be defined as: $\begin{matrix} {{R_{c}(\alpha)} = {R\left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \\ {= \begin{bmatrix} {n_{1}^{2} + {\left( {1 - n_{1}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{2}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{2}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{2}^{2} + {\left( {1 - n_{2}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{1}{\sin \left( {\frac{\alpha}{2\pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} - {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{1}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{3}^{2} + {\left( {1 - n_{3}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \end{bmatrix}} \end{matrix}$

[0035] Angle α (FIG. 4) is the rotation angle of current column Q in the XZ plane, which is determined by the arctangent of x₁/z₁ of current pixel P_(f).

[0036]FIG. 5 shows that the computer traces the current pixel P_(f) back to origin O to determine a ray OP_(f) that passes through the current pixel P_(f) and a pixel P_(c) on the original stitched images. The computer then determines a ray OP_(f)′ that would have been rotated by compensation matrix R_(c)(a) to coincide with ray OP_(f). The computer traces ray OP_(f)′ to its intersection with the original stitched picture to find a pixel P_(o). The computer then paints the pixel color values of pixel P_(o) to the current pixel P_(f) on the final stitched images 102.

[0037] In action 216, the computer determines if the current pixel P_(f) is the last pixel in the current column Q. If it is not, action 216 is followed by action 218. If the current pixel P_(f) is the last pixel in the current column Q, then action 216 is followed by action 220.

[0038] In action 218, the computer selects a next pixel in the current column. Action 218 is followed by action 214 and the above actions cycle until all the pixels in the current column have been compensated.

[0039] In action 220, the computer determines if the current column in the last column on cylindrical surface 102. If it is not, action 220 is followed by action 222. If the current column is the last column, then action 220 is followed by action 224, which ends method 200.

[0040] In action 222, the computer selects a next column on cylindrical surface 102. Action 222 is followed by action 212 and the above actions cycle until all the pixels in all the columns have been compensated.

[0041] One embodiment of method 200 implemented in pseudo code is provided in the attached index.

[0042] Various other adaptations and combinations of features of the embodiments disclosed are within the scope of the invention. Numerous embodiments are encompassed by the following claims. Index for(x1 = count − 1; x1 > 0; x1 −−) { pR1 = &(pMatrix−>GetElement(x1 % count, 0)−>Rotate); *pR1 = pMatrix−>GetElement(x1 − 1, 0)−>RotateH; for(x2=count − 1; x2 > x1; x2−−) { pR2 = &(pMatrix−>GetElement(x2 % count, 0)−>Rotate); Mul(pR1, pR2, &R3); *pR2 = R3; } } pR1 = &(pMatrix−>GetElement(0, 0)−>Rotate); identity(pR1); double* A = new double[3 * 3]; pR1 = &(pMatrix−>GetElement(count − 1, 0)−>Rotate); pR2 = &(pMatrix−>GetElement(count − 1, 0)−>RotateH); Mul(pR1, pR2, &R3); *(A) = R3.r11; //A = inv(pR1); *(A+1) = R3.r21; *(A+2) = R3.r31; *(A+3) = R3.r12; *(A+4) = R3.r22; *(A+5) = R3.r32; *(A+6) = R3.r13; *(A+7) = R3.r23; *(A+8) = R3.r33; 3×3 orthogonal matrix “rotation axis” representation The following two functions implemented the conversion between an orthogonal matrix and it's “rotation axis” representation. //////////////////////////////////////////////// // // A unit orthogonal matrix(3×3) represented by the rotation axis and // the rotation angle // 1. [A]3×3 is the input unit orthogonal matrix; // 2. [n]3×1 is the output rotation axis; // 3. *pDegree is the output rotation angle; // 4. Return value is TRUE if success, // or else is TRUE. // //////////////////////////////////////////////// BOOL UOM2AxisAngle(double *A, double *n, double *pDegree) { const double PI = 3.1415926; double d1, d2, d3; d1 = *(A+4) + *(A+8) − 1.0; d2 = *(A) + *(A+8) − 1.0; d3= *(A) + *(A+4) − 1.0; if(*(A) < d1 ∥ *(A+4) < d2 ∥ *(A+8) < d3) { *n = 1.0; *(n+1) = 0.0; *(n+2) = 0.0; *pDegree = 0.0; return TRUE; } double trace, cs, ss; trace = MatrixTrace(A, 3); cs = (trace − 1.0)/2.0; if(cs == 1.0) { *n = 1.0; *(n+1) = 0.0; *(n+2) = 0.0; *pDegree = 0.0; } else if(cs == −1.0) { *n = 1.0; *(n+1) = 0.0; *(n+2) = 0.0; *pDegree = 3.14; } else { *pDegree = acos(cs); ss = sin(*pDegree); double temp = ss * 2.0; *n = (*(A+7) − *(A+5))/temp; //A(3, 2) − A(2, 3) *(n+1) = (*(A+2) − *(A+6))/temp; //A(1, 3) − A(3, 1) *(n+2) = (*(A+3) − *(A+1))/temp; //A(2, 1) − A(1, 2) } double norm = sqrt(*n * *n + *(n+1)* *(n+1) + *(n+2)* *(n+2)); *n = *n/norm; *(n+1) = *(n+1)/norm; *(n+2) = *(n+2)/norm; if((*pDegree > PI/4.0) ∥ (*pDegree <− PI/4.0)) *pDegree = 0.0; return TRUE; } //////////////////////////////////////////////// // // Using a rotation axis and a rotation angle can generate // a unit orthogonal matrix(3×3) // 1. [A]3×3 is the output unit orthogonal matrix; // 2. [n]3×1 is the input rotation axis, n should be a unit vector; // 3. degree is the input rotation angle. // //////////////////////////////////////////////// void AxisAngle2UOM(double *A, double *n, double degree) { double cs, ss, temp; double n11, n12, n13, n22, n23, n33; cs = cos(degree); ss = sin(degree); temp 1.0 − cs; n11 = *(n)* *(n); n12 = *(n)* *(n+1); n13 = *(n)* *(n+2); n22 = *(n+1)* *(n+1); n23 = *(n+1)* *(n+2); n33 = *(n+2)* *(n+2); *(A) = n11 * temp + cs; *(A+1) = n12 * temp − *(n+2) * ss; *(A+2) = n13 * temp + *(n+1) * ss; *(A+3) = n12 * temp + *(n+2) * ss; *(A+4) = n22 * temp + cs; *(A+5) = n23 * temp − *(n) * ss; *(A+6) = n13 * temp − *(n+1) * ss; *(A+7) = n23 * temp + *(n) * ss; *(A+8) = n33 * temp + cs; }  Calculate the final stitch image layout In this step, we apply scan line technology to compute the final stitch image layout for the coming backward pixel-rendering algorithm. The layout datum is stored in the following structures. struct LineSegment { LONG e1; // start point LONG e2; // end point }; struct DLineSegment { double e1; // start degree double e2; // end degree }; class CScanRegion { public: // Region dimensions RECT rect; // Convenience points LineSegment* pSegH0; LineSegment* pSegV0; DLineSegment* pSegD0; protected: // Buffer headers LineSegment* pSegH; LineSegment* pSegV; DLineSegment* pSegD; public: CScanRegion( ); ˜CScanRegion( ); Create(RECT rcRegion); };  Compensate the current pixel with R_(C) matrices LONG y_e1 = pScan[c].pSegV0[x].e1; LONG y_e2 = pScan[c].pSegV0[x].e2; double d_e1 = pScan[c].pSegD0[x].e1; double d_e2 = pScan[c].pSegD0[x].e2; double theta; if(fabs(d_e2 − d_e1) < 1.0e-2) theta = 0.0; else theta = (d_e2 − d_e1)/(y_e2 − y_e1); LONG x_wrap = x; for (y = y_e1; y <= y_e2; y++) { pict.x = x_wrap; pict.y = y; CartesianCoord cart1, cart2; Picture2Cartesian(&pict, &cart1); double* A = new double[3*3]; AxisAngle2UOM(A, pAxis d_e1 + (y − y_e1) * theta); if(fabs(Degree) > 1.0e-6) { double delta = (d_e1 + (y − y_e1) * theta)/Degree; cart2.x = pict.r * sin(delta * 2 * PI); cart2.z = −pict.r * cos(delta * 2 * PI); cart2.y = (cart1.y − *(A+3) * cart2.x − *(A+5) * cart2.z)/*(A+4); Cartesian2Picture(&cart2, &pict); } else { cart2.x = *A * cart1.x + *(A+3) * cart1.y + *(A+6) * cart1.z; cart2.y = *(A+1) * cart1.x + *(A+4) * cart1.y + *(A+7) * cart1.z; cart2.z = *(A+2) * cart1.x + *(A+5) * cart1.y + *(A+8) * cart1.z; Cartesian2Picture(&cart2, &pict); } delete [ ] A; } Picture2RealFilm(&pict, &film, R); 

What is claimed is:
 1. A method for creating a 360 degree panoramic image from a plurality of images, comprising: determining a gross rotation error ΔR between a first image and a last image, wherein the gross rotation error ΔR is a rotation necessary to rotate the first image to match the last image; and spreading the gross rotation error ΔR to each pixel of the panoramic image.
 2. The method of claim 1, wherein said spreading the gross rotation error ΔR comprises determining a compensation matrix R_(c) for each pixel in the 360 degree panoramic image.
 3. The method of claim 3, wherein said determining a compensation matrix R_(c) for each pixel in the 360 degree panoramic image comprises determining a compensation matrix R_(c) for each column of pixels in the 360 degree panoramic image.
 4. The method of claim 3, wherein said determining a compensation matrix R_(c) for each column of pixels in the 360 degree panoramic image comprises: determining a rotation angle θ₀ and rotational axis n₀ for the gross rotational error ΔR; determining a rotation angle α of the column; and determining a compensation matrix R_(c) for each column using the following formula: ${R_{c}(\alpha)} = {\begin{bmatrix} {n_{1}^{2} + {\left( {1 - n_{1}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{2}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{2}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{2}^{2} + {\left( {1 - n_{2}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{1}{\sin \left( {\frac{\alpha}{2\pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} - {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{1}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{3}^{2} + {\left( {1 - n_{3}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \end{bmatrix}.}$


5. The method of claim 4, wherein said determining a rotation angle θ₀ and rotational axis n₀ for the gross rotational error ΔR comprises using a plurality of relative rotation matrices between adjacent images from the plurality of images to calculated the θ₀ and the n₀.
 6. The method of claim 4, wherein said spreading the gross rotation error ΔR further comprises: tracing a first pixel in a column on the 360 degree panoramic image to a camera optical center of the plurality of images to form a first ray; determining a second ray originating from the camera optical center that would be rotated by the compensation matrix R_(c) to coincide with the first ray; and tracing the second ray to an intersection with a second pixel on one of the plurality of images; and painting the first pixel with color values of the second pixel.
 7. A method for creating a 360 degree panoramic image from a plurality of images, comprising: determining a gross rotation error ΔR between a first image and a last image, wherein the gross rotation error ΔR is a rotation necessary to rotate the first image to match the last image; determining a rotation angle θ₀ and rotational axis n₀ for the gross rotational error ΔR, comprising using a plurality of relative rotation matrices between adjacent images from the plurality of images to calculated the θ₀ and the n₀; determining a rotation angle α of the column; determining a compensation matrix R_(c) for each column using the following formula: ${R_{c}(\alpha)} = \begin{bmatrix} {n_{1}^{2} + {\left( {1 - n_{1}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{2}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{1}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} + {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{2}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{3}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{2}^{2} + {\left( {1 - n_{2}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \quad \theta}} \right)}} - {n_{1}{\sin \left( {\frac{\alpha}{2\pi}\theta_{0}} \right)}}} \\ {{n_{1}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} - {n_{2}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {{n_{2}{n_{3}\left( {1 - {\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}} \right)}} + {n_{1}{\sin \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} & {n_{3}^{2} + {\left( {1 - n_{3}^{2}} \right){\cos \left( {\frac{\alpha}{2\quad \pi}\theta_{0}} \right)}}} \end{bmatrix}$

tracing a first pixel in a column on the 360 degree panoramic image to a camera optical center of the plurality of images to form a first ray; determining a second ray originating from the camera optical center that would be rotated by the compensation matrix R_(c) to coincide with the first ray; and tracing the second ray to an intersection with a second pixel on one of the plurality of images; and painting the first pixel with color values of the second pixel. 